package org.common.aspect;

/**
 * ClassName: LogInfoAspect
 * Package: org.common.aspect
 * Description:
 *
 * @Author: @weixueshi
 * @Create: 2024/7/19 - 11:38
 * @Version: v1.0
 */

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.common.annotation.LogInfoAnnotation;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 日志打印切面类
 */
@Slf4j
@Aspect
@Component
public class LogInfoAspect {

    /**
     * 定义切点
     */
    @Pointcut("@annotation(org.common.annotation.LogInfoAnnotation)")
    public void pointcut() {
    }

    /**
     * 环绕通知
     * @param joinPoint 切点
     * @return Object
     */
    @Around("pointcut()")
    public Object logInfoAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //返回值
        Object result = null;

        //记录开始时间
        long startTime = System.currentTimeMillis();

        //执行方法
        result = joinPoint.proceed();

        //记录结束时间
        long endTime = System.currentTimeMillis();
        //执行时长(毫秒)
        long costTime = endTime - startTime;

        // 获取请求URL
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestUrl = request.getRequestURL().toString();

        //获取注解标记的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取方法名
        Method method = signature.getMethod();

        //获取方法上的注解
        LogInfoAnnotation logInfoAnnotation = method.getAnnotation(LogInfoAnnotation.class);
        if(logInfoAnnotation != null) {
            //接收参数
            StringBuffer jsonParams = new StringBuffer();
            //获取方法上的形参数据
            Object[] args = joinPoint.getArgs();
            //获取方法上的参数名
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discoverer.getParameterNames(method);

            for (int i = 0; i < parameterNames.length; i++) {
                jsonParams.append(parameterNames[i]).append("=").append(args[i].toString()).append(" ");
            }
            //将返回结果序列化
            String jsonResult = null;
            if(result != null) {
                jsonResult = new ObjectMapper().writeValueAsString(result);
            }else{
                jsonResult = "null";
            }

            //打印日志，根据需要打印日志
            log.info("\n 方法执行分析报告如下：" +
                    "\n 类名：" + joinPoint.getTarget().getClass().getName() +
                    "\n 方法名：" + method.getName() +
                    "\n 请求URL：" + requestUrl +
                    "\n 执行耗时：" + costTime + "毫秒" +
                    "\n 输入参数：" + jsonParams +
                    "\n 输出结果：" + jsonResult);
        }
        return result;
    }
}
